package org.bouncycastle.pqc.jcajce.provider.test;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.SecureRandom;
import java.security.Security;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

import junit.framework.TestCase;
import org.bouncycastle.asn1.ASN1BitString;
import org.bouncycastle.asn1.ASN1OctetString;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.pqc.jcajce.interfaces.DilithiumKey;
import org.bouncycastle.pqc.jcajce.interfaces.DilithiumPrivateKey;
import org.bouncycastle.pqc.jcajce.spec.DilithiumParameterSpec;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.Strings;
import org.bouncycastle.util.encoders.Hex;

/**
 * Dilithum now in BC provider
 */
public class DilithiumTest
    extends TestCase
{
    byte[] msg = Strings.toByteArray("Hello World!");

    public void setUp()
    {
        if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null)
        {
            Security.addProvider(new BouncyCastleProvider());
        }
    }

    public void testPrivateKeyRecovery()
            throws Exception
    {
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("Dilithium", "BC");

        kpg.initialize(DilithiumParameterSpec.dilithium3, new DilithiumTest.RiggedRandom());

        KeyPair kp = kpg.generateKeyPair();

        KeyFactory kFact = KeyFactory.getInstance("Dilithium", "BC");

        DilithiumKey privKey = (DilithiumKey)kFact.generatePrivate(new PKCS8EncodedKeySpec(kp.getPrivate().getEncoded()));

        assertEquals(kp.getPrivate(), privKey);
        assertEquals(kp.getPrivate().getAlgorithm(), privKey.getAlgorithm());
        assertEquals(kp.getPrivate().hashCode(), privKey.hashCode());

        assertEquals(((DilithiumPrivateKey)kp.getPrivate()).getPublicKey(), ((DilithiumPrivateKey)privKey).getPublicKey());

        ByteArrayOutputStream bOut = new ByteArrayOutputStream();
        ObjectOutputStream oOut = new ObjectOutputStream(bOut);

        oOut.writeObject(privKey);

        oOut.close();

        ObjectInputStream oIn = new ObjectInputStream(new ByteArrayInputStream(bOut.toByteArray()));

        DilithiumKey privKey2 = (DilithiumKey)oIn.readObject();

        assertEquals(privKey, privKey2);

        assertEquals(kp.getPublic(), ((DilithiumPrivateKey)privKey2).getPublicKey());
        assertEquals(kp.getPrivate().getAlgorithm(), privKey2.getAlgorithm());
        assertEquals(kp.getPrivate().hashCode(), privKey2.hashCode());

        assertEquals(((DilithiumPrivateKey)privKey).getPublicKey(), ((DilithiumPrivateKey)privKey2).getPublicKey());
    }

    public void testPublicKeyRecovery()
            throws Exception
    {
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("Dilithium", "BC");

        kpg.initialize(DilithiumParameterSpec.dilithium5, new DilithiumTest.RiggedRandom());

        KeyPair kp = kpg.generateKeyPair();

        KeyFactory kFact = KeyFactory.getInstance("Dilithium", "BC");

        DilithiumKey pubKey = (DilithiumKey)kFact.generatePublic(new X509EncodedKeySpec(kp.getPublic().getEncoded()));

        assertEquals(kp.getPublic(), pubKey);
        assertEquals(kp.getPublic().getAlgorithm(), pubKey.getAlgorithm());
        assertEquals(kp.getPublic().hashCode(), pubKey.hashCode());

        ByteArrayOutputStream bOut = new ByteArrayOutputStream();
        ObjectOutputStream oOut = new ObjectOutputStream(bOut);

        oOut.writeObject(pubKey);

        oOut.close();

        ObjectInputStream oIn = new ObjectInputStream(new ByteArrayInputStream(bOut.toByteArray()));

        DilithiumKey pubKey2 = (DilithiumKey)oIn.readObject();

        assertEquals(pubKey, pubKey2);
        assertEquals(pubKey.getAlgorithm(), pubKey2.getAlgorithm());
        assertEquals(pubKey.hashCode(), pubKey2.hashCode());
    }

    public void testRestrictedSignature()
        throws Exception
    {
        doTestRestrictedSignature("DILITHIUM2", DilithiumParameterSpec.dilithium2, DilithiumParameterSpec.dilithium5);
        doTestRestrictedSignature("DILITHIUM3", DilithiumParameterSpec.dilithium3, DilithiumParameterSpec.dilithium5);
        doTestRestrictedSignature("DILITHIUM5", DilithiumParameterSpec.dilithium5, DilithiumParameterSpec.dilithium2);
    }

    private void doTestRestrictedSignature(String sigName, DilithiumParameterSpec spec, DilithiumParameterSpec altSpec)
        throws Exception
    {
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("Dilithium", "BC");

        kpg.initialize(spec, new SecureRandom());

        KeyPair kp = kpg.generateKeyPair();

        Signature sig = Signature.getInstance(sigName, "BC");

        sig.initSign(kp.getPrivate(), new SecureRandom());

        sig.update(msg, 0, msg.length);

        byte[] s = sig.sign();

        sig = Signature.getInstance(sigName, "BC");

        assertEquals(sigName, sig.getAlgorithm());

        sig.initVerify(kp.getPublic());

        sig.update(msg, 0, msg.length);

        assertTrue(sig.verify(s));

        kpg = KeyPairGenerator.getInstance("Dilithium", "BC");

        kpg.initialize(altSpec, new SecureRandom());

        kp = kpg.generateKeyPair();

        try
        {
            sig.initVerify(kp.getPublic());
            fail("no exception");
        }
        catch (InvalidKeyException e)
        {
            assertEquals("signature configured for " + spec.getName(), e.getMessage());
        }
    }

    public void testRestrictedKeyPairGen()
        throws Exception
    {
        doTestRestrictedKeyPairGen(DilithiumParameterSpec.dilithium2, DilithiumParameterSpec.dilithium5);
        doTestRestrictedKeyPairGen(DilithiumParameterSpec.dilithium3, DilithiumParameterSpec.dilithium5);
        doTestRestrictedKeyPairGen(DilithiumParameterSpec.dilithium5, DilithiumParameterSpec.dilithium2);
    }

    private void doTestRestrictedKeyPairGen(DilithiumParameterSpec spec, DilithiumParameterSpec altSpec)
        throws Exception
    {
        KeyPairGenerator kpg = KeyPairGenerator.getInstance(spec.getName(), "BC");

        kpg.initialize(spec, new SecureRandom());

        KeyPair kp = kpg.generateKeyPair();

        assertEquals(spec.getName(), kpg.getAlgorithm());
        assertEquals(spec.getName(), kp.getPublic().getAlgorithm());
        assertEquals(spec.getName(), kp.getPrivate().getAlgorithm());

        kpg = KeyPairGenerator.getInstance(spec.getName(), "BC");

        try
        {
            kpg.initialize(altSpec, new SecureRandom());
            fail("no exception");
        }
        catch (InvalidAlgorithmParameterException e)
        {
            assertEquals("key pair generator locked to " + spec.getName(), e.getMessage());
        }
    }

    public void testDilithiumRandomSig()
            throws Exception
    {
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("Dilithium", "BC");

        kpg.initialize(DilithiumParameterSpec.dilithium2, new SecureRandom());

        KeyPair kp = kpg.generateKeyPair();

        Signature sig = Signature.getInstance("Dilithium", "BC");

        sig.initSign(kp.getPrivate(), new SecureRandom());

        sig.update(msg, 0, msg.length);

        byte[] s = sig.sign();

        sig = Signature.getInstance("Dilithium", "BC");

        sig.initVerify(kp.getPublic());

        sig.update(msg, 0, msg.length);

        assertTrue(sig.verify(s));
    }

    /**
count = 0
seed = 061550234D158C5EC95595FE04EF7A25767F2E24CC2BC479D09D86DC9ABCFDE7056A8C266F9EF97ED08541DBD2E1FFA1
mlen = 33
msg = D81C4D8D734FCBFBEADE3D3F8A039FAA2A2C9957E835AD55B22E75BF57BB556AC8
pk = 1C0EE1111B08003F28E65E8B3BDEB037CF8F221DFCDAF5950EDB38D506D85BEF6177E3DE0D4F1EF5847735947B56D08E841DB2444FA2B729ADEB1417CA7ADF42A1490C5A097F002760C1FC419BE8325AAD0197C52CED80D3DF18E7774265B289912CECA1BE3A90D8A4FDE65C84C610864E47DEECAE3EEA4430B9909559408D11A6ABDB7DB9336DF7F96EAB4864A6579791265FA56C348CB7D2DDC90E133A95C3F6B13601429F5408BD999AA479C1018159550EC55A113C493BE648F4E036DD4F8C809E036B4FBB918C2C484AD8E1747AE05585AB433FDF461AF03C25A773700721AA05F7379FE7F5ED96175D4021076E7F52B60308EFF5D42BA6E093B3D0815EB3496646E49230A9B35C8D41900C2BB8D3B446A23127F7E096D85A1C794AD4C89277904FC6BFEC57B1CDD80DF9955030FDCA741AFBDAC827B13CCD5403588AF4644003C2265DFA4D419DBCCD2064892386518BE9D51C16498275EBECF5CDC7A820F2C29314AC4A6F08B2252AD3CFB199AA42FE0B4FB571975C1020D949E194EE1EAD937BFB550BB3BA8E357A029C29F077554602E1CA2F2289CB9169941C3AAFDB8E58C7F2AC77291FB4147C65F6B031D3EBA42F2ACFD9448A5BC22B476E07CCCEDA2306C554EC9B7AB655F1D7318C2B7E67D5F69BEDF56000FDA98986B5AB1B3A22D8DFD6681697B23A55C96E8710F3F98C044FB15F606313EE56C0F1F5CA0F512E08484FCB358E6E528FFA89F8A866CCFF3C0C5813147EC59AF0470C4AAD0141D34F101DA2E5E1BD52D0D4C9B13B3E3D87D1586105796754E7978CA1C68A7D85DF112B7AB921B359A9F03CBD27A7EAC87A9A80B0B26B4C9657ED85AD7FA2616AB345EB8226F69FC0F48183FF574BCD767B5676413ADB12EA2150A0E97683EE54243C25B7EA8A718606F86993D8D0DACE834ED341EEB724FE3D5FF0BC8B8A7B8104BA269D34133A4CF8300A2D688496B59B6FCBC61AE96062EA1D8E5B410C5671F424417ED693329CD983001FFCD10023D598859FB7AD5FD263547117100690C6CE7438956E6CC57F1B5DE53BB0DC72CE9B6DEAA85789599A70F0051F1A0E25E86D888B00DF36BDBC93EF7217C45ACE11C0790D70E9953E5B417BA2FD9A4CAF82F1FCE6F45F53E215B8355EF61D891DF1C794231C162DD24164B534A9D48467CDC323624C2F95D4402FF9D66AB1191A8124144AFA35D4E31DC86CAA797C31F68B85854CD959C4FAC5EC53B3B56D374B888A9E979A6576B6345EC8522C9606990281BF3EF7C5945D10FD21A2A1D2E5404C5CF21220641391B98BCF825398305B56E58B611FE5253203E3DF0D22466A73B3F0FBE43B9A62928091898B8A0E5B269DB586B0E4DDEF50D682A12D2C1BE824149AA254C6381BB412D77C3F9AA902B688C81715A59C839558556D35ED4FC83B4AB18181F40F73DCD76860D8D8BF94520237C2AC0E463BA09E3C9782380DC07FE4FCBA340CC2003439FD2314610638070D6C9EEA0A70BAE83B5D5D3C5D3FDE26DD01606C8C520158E7E5104020F248CEAA666457C10AEBF068F8A3BD5CE7B52C6AF0ABD5944AF1AD4752C9113976083C03B6C34E1D47ED69644CAD782C2F7D05F8A148961D965FA2E1723A8DDEBC22A90CD783DD1F4DB38FB9AE5A6714B3D946781643D317B7DD79381CF789A9588BB3E193B92A0B60D6B07D047F6984B0609EC57543C394CA8D5E5BCC2A731A79618BD1E2E0DA8704AF98F20F5F8F5452DDF646B95B341DD7F0D2CC1FA15BD9895CD5B65AA1CB94B5E2E788FDA9825B656639193D98328154A4F2C35495A38B6EA0D2FFAAA35DF92C203C7F31CBBCA7BD03C3C2302190CECD161FD49237E4F839E3F3
sk = 1C0EE1111B08003F28E65E8B3BDEB037CF8F221DFCDAF5950EDB38D506D85BEF394D1695059DFF40AE256C5D5EDABFB69F5F40F37A588F50532CA408A8168AB187D0AD11522110931494BF2CAEAE36979711BC585B32F08C78496F379D604D5321C8C62B59EDC23AE1FC7742135918E01B02E411630E26E675400D5AD2C776FCC0A6711A966C11312AD9A821D8086542A600A4B42C1940720242628106210A43852331709308108B188C022492C1B28412C4218B042181C8610248059C9201C0348819326C582046891868A2C28D82346A1C094200A28CE3A6491C112CC24812E0902191985062C084622451CA062C64240E1BB3312496854B4606DB2668C38268441046C9B6211404811445502442084422710B92459AA0811A91709C241003957004C504C82692D29200C0B260C0A26809190AA2300E188969E0008DD84862DA14712018051907440412409B1240118010D142819928508B1091022464A0206D1246211C838C1B4769010690CC062481846920982C24120521B15041360298446ED1A63111056AD3A840CAA84C62B00003134A53344614194004C54CE306695AB08961168ECB10808B168ED990640B94602483851AB30454262251B8251C424A0B814842C4445A102023808409B7254CC64814854D19380E601651D8326A0A918908C170E0964D18468C01328D91C4054A0061230868A2104210A8611306218A248E620689C9B24508278451200D980466DC42054424852426282221612016090BA62C0A1144E0928158480D422210A006098B246E81288CC0248090308D8436404CA68450042494B68DA2926D18B344A00085E3B805140504A4C290842281C3262D0B2066CC903198382810166CC13445C0102224C688034632D840901C20680415289A188144988D9C206E9C302CC1B820614221080310A0C28C58128553204C0330814CA48D44C08D51404C1CA72C440865A03840DA20808106858C260DE2A88C9C4411594228C42604441426A1426408C0851101869B483199B20C80464459A88C0042089882900AB54562244812960544124600C88813A061E1284D0AB9914B962099B84400314E98128500B60183A00D14150E1881101901224A06681A498DE1A28411C63121262591A06D030524A1B6089444724334125BB42041B650D0888D0B074D1C94644C208E8B8808E0300944200549864D03134E19C9840937611A43684A80900204311C1742184080C8308EE1A241C33404A3282251247188D6FEF46712CA182872AB2919678AFF9D94E743E063A39E0C35CAF72A7F2EDA28E65858520D5D8467DE747CF340653B52C268F55413F5ADDC7D49011EC33EDD537423A84288869337AEA0781A124269071451722DB3BB8F2CE5B1552F83D2AF07F25613918A9F4E6F1257603888E589308CA5F95F07143D23BAAE17520B36B6E0E94FAF6845EB2131AEC383E63BC8644EE5F1ACCBA82F9211E57AFCBF509C1131A37466BC91B357DCBBBC14CCC319C4CC6AC75FCDC82C6596D07770C8277AD370B192A0B4E05F812E0E265D2912AA29F03FC9F72DFA69C9B1291A3FC583642B235F6991A954788347F60A0328C48ECEE51BA02DFF323ABD911667CB14549B618F1C5D250CAC9E35E071601992FBEC0BAE6F74213081404744D12F2A0E04BDB265E0924CADA40D1FA1F38ACA4606BFD4575712B8260A456FDDEEEFE7CA259BCDA97B9B939A5FD2889C9B49FB7D4E3553DEA61B3339BD0E6B16BF3BB227103BF9202E72DC502E28F7CE1559A4631F372520324E4EBA07545F78BF4D94B0E5B8BF51B8F176533D5CFEA5232F283A47605FA65DDB17C891C251011C4E98EEB6EB00CB65BA31C8F025C87A9FE02DBC10C5D83A065EBA5D7B2A19D5A1CB2C160AE166E867F2AF8C7D49D63FB83A614957FC0A3B5A5C74990E9A2B02120C7E6DE37E155FB472F50F0A45E47CF5F9D7A4C82982C9DC86AE877C3FD1885943E439FB003C7A9A42F71B4FF6F0A28B140CBDBA6E71B13AC31B23DE9EAB7837E15A69F833EB7B56A71D8BC2CAF1F2A31C345BD5F46EE013A7C689372337191DAA800C0AC6C46C9FF688B1A01347F257C474AA3D97C1D63A8C00E0A37B681673F57C1C9C8FCCD46F174C74A29D84CEB71F7E6B2F8CD2B089ED43F7C96DAE81A223418C20B16F1DF3D1A978AE28F6DF35EC559D04D20EC74B224AEA31A289B015B069E9CBBBF7CF6DE94CFB2A96E4AE3462C96003CDDA87DB561AF2CE3C0BA1D90413FDCE3CCF4390C02C1CB9F654F4820EC33015457D4A629FBF39419CAB7642D6885E103FCE0D4206CCE7C12C6FC44FA33AD0864C3371A7CBE820E3B371B656A38F2E7FF18FE4A50C8AB3F85D783FB57835CED8490B84EE0D99AF0D64C483CEB6366FF54F8AC8A40DB1AFA573A4FB326C74F0236ECEF3DA7120665CCE05DD654B5071723A8348E7CD7793513819B61CB64E1328E8B22E7664BD6B41B5710D19EA8809D4450850E907DFC4D0B75F588CECE962E9E0937CE1402446A4D2891A46E6617FB29D4FCD712606F7819ECA60F7E0D5B19E7FFB57C73C16FFEEB90038410CB9FCBB5E9D51EB3EB6297E9FF6AB7088FE2D9B237BC24CF7F8290118A5E0E00A0B903FB6375C848176CD0A8C8875CC59199CDA11A87A78F65CC404330B087571FD0633E27129FDAB5A8A1F793E52412B0083FD5C74DB3CF60C2543CE7C91B2800E40203F8D99FE5FDE5B108E7EDC80EBB9BB34986EC5C5A8F580E75752907FF0F294C866C2CF1F362E840B6881BD43219201781C63B0039A95BCFB4A0FECE569DF00523CE9C084B022B3B022242E28419796ACF0A0C995F948DBFFFD30D77ED105A3C9943C406B305BC81A6A248A291548F2A67F438D966A57D53F4B7BE15354E581BE16F7AD64D164E85787DF5849C810AFC28D06482F441B5FDE3DB2ED36DD25AA6664D4D43FFA32EDA25689C9F4A5D514FC66231C5401520922524438EF1DC78D693C9718DEBBD243312674C899F18910E389C8EBE505824BCC42CD4A9ACE193768220219011F3B1F335427BFF9E8BDED5C08711A09C2B71CB964C56A8393BFD2B56E9B6B2F513E682587DC1B8ED196066326871025628036700063176D345DE384E182D6C417A32AB11095EF59BB4D171B9CF81D17AC42664DED933CCB722C69857FFC53C8E7F2474B0CB2DFF2DDC8A5C601C84A701981199BCCF74112A6EC062C4FEB601A028AF01032ADB6BD15D4C2B9550AA850AD62CCC3A3665D5212B12E0FD5C5326A1E5EB1F10D557D94605E8E3F356E08FF7FD884ED3C4205463594C9AF2F39E4B1274695234B54EECED93F460EDF1A13C2CB4B17D322F6F79FE16F0357C1C4739863E796791F8647FABF730AB00E0DA509706D94571740F61F7BAF366D2774C9B5B8C61DD6BE9819A6028B264BB2E4AEA54B56D4ECAB5B528CE0C0C0CCDB73023352CB00445BAB6F7467B4644D4361C464FAC6B5B137D32391021B475FCB5F31774FD8ECABDF65475F25574C65559CB331F41C0F498B74DD941C344C50D8E64F9578714A32561FAACEAF78148E6DA4B566826925714B17108AFDD546385A3CD454D5CAA16960916282A47C4315CE236BD9E3255C604EBDC39772DB5CE0B236
smlen = 2453
sm = 3D7F3A26A1A6DC133D036981F7406AE0858C74121BDA303DD5DA8D9ACB68409F1051C88C4B163C252DDB5E78E8EB867279A17289B34CD3BA4AA199AE56B28356EE49FF8304086E7CAA6B0DBA7EF60AD5ED9411A82FF9BE7D6177908977EF67CCD532A4723F125F4748B350C3948F2AC6C4F006CACB8C92CDC0941CDE2EFB4B732BF85954F4BA8417561403A863E0261A29D79987859976B4F8BDC7BC5EF215A07ED6004343CC7CFE79ECC7143AFD525CA35ADB5D603CAF97BD0A80104E4DE48FB41668F314415096E3547554D25FA09E9C14E60BD15A6DDCD0710A0FED464079229CA65A636E15D9215283767241FB6EED385B51416660F95AA8A619B55FA38B9A7CB710FBC0AD6237C72BECFB9D3182229E06A696B5E32B4B2EF2164349B54266BA9734EAD45387CA913507E3E75B49FEA7D3BD03A7EEE2EE8AFE048DD9E38686D5A1C5DB31A8FC960FD3575496CD301CDB952D8CF85792DEDF7FF6FA5BBF5101288EE80AFE1183B4A6689AE72E66B50393DC3345DF62BA2DCB999158FD8FD9A75AF95ED9C3EA325FEC21C5B611B267B938AE02580C72FB94E8910DBA88A32811B6FEE8A04355EBDEEDFAEC85F5FFDD6811FA4A3CC6323CDD93E6CE7F98688022401AF54288BF888B289F972FB98ECABF0D2C364344BBD2FFDAAE518A66370FF6BCA7D996B03BA3140890840E5EDD3EB98672D266F47A2E15255656CA978F14943BD40B1B21041173F6058391AA259D7E4F76C10DA3CF3AEE9B71A127A55DCB80AD822337C1D79C763CD7774A31A58743A4797D52DD3959A66BDB08338D007E2CA7CD19B0C553045C40D3E7AB0D318378799DD9A02B6C2B0C7C9B8DB986668598605163709193AC4DF5B19A5CE28BDD7CAD59AFF10FAA2220284DBE5D4C7FDF2792C559A6076865081D5F4513CFAE092458FD410E18BE1BC5F970660BB0C89C020079C121A1953C2AF9298A6342D1C47C413B4B3C35DD91358DEBE7DC109F35A3512514DBEBB544851709EC1A750550422F1C9FA40B50DE08DBFDE90593D229E01BD9F0756CBA1EBACB8CC2139D4CADC778BF937BD524E8845ECF964A04F7C43CD056F6A7A810C77C8B8FA73359CD1EB8670E1AF7F4BC247B7EC515C1BBA404B76635762D4E0EF451150C8A58437C06FD2C4154A00D63408F1EEE5D1B67F7F4893C158A765237C4FDB215CC0E3F4D60437AF43EF9AC575C0C6B85A93D5493DAB60961D55C4BEACE3A907597CCFC7C6EFB5453DCF83796AFD070322A650BDEA47B76DFF7756CEA567961830E7DC49B2A8923C59BECADD06435D6EFBC7F5307FDA057DAEB1C5B4F6E64D8E141A46090C9EF90D3816453F975C3C7158560DAFEE463148AC0E1E5351020F0A7C08A7C14C1AA9581C936EF845E011E82DE64FB4CB49DA4E3C8D079EF7DEEB41665C6ED43A4F161CBB795AC4FE1A67D6FE18CFB1A15BC02066A2598EFAA9FACC5BDD7257C68E309B2E2622D8C647A3D4656DEB71D414100049AA42C991F997F81A9B391449C4DAB874F9F309463A508E950501590FBC2ED4E80C2D63CE0DB72DE74D7CF9AAC845BE2502B89247D971EB5169A583677CC88C569067E726F9DDD1B49E80220F5B764CE4A32049E20C7FC2A573BFB911EB4AF50B9C2E1F5195AE76FC2F54D0BA33F2CDE2DB3084C5E5F25155D8D81082EAEF09C598A699373B5CCFD7DFB9ED2DDA4DD4681B073B24D6135D65A8ECB41CEB156B8D8F77A4DA1747239D0E7DE48441E90C62FB26DDB0E802DEEA997A6A2569885D0CBB2833A12D4BE92FFCB9AE3A3CFB01874C6A82427A7052ED0E6652DA9BA95280E24B65F8EAB174812011DD12D9062B1004C60DE85685D7D41FB5F04E9707E034A305B60145DF6686818CCA3457BA1DEEE0235D3B1D026F69A2AC556A1A93455F712C3A737BB4A30CE52F0204AB79F65B3E305EF89686D213B08AA538F4BA486C8709C8627C51DE86596D8EB035D807AFFC6F68D88E0B145DEABE8AAAEB411D085827E7CB47E3C568207FBEE7BA9568B414C0CADB05DA7D36F83037847A9F7233135F49FC14496485071CA5C5A0D1725C016E7482B6F9892D64FF76C6AF73330EE4C654654943F9966DAF3356C7ED8E4A0DD2F58B73B144D5FA286ADBE2A24776FEB78A4DD241EC3BF1DF78D5DDE6A48F8655F6FFC7D28543CA41F52F15CDC7CF092F48CEA91356D0EB1444A3290451033871F0006373F5A62CE9586ED95D3E361EFAD629B3A4D2C3643405DB4B7F837B7128C11E55C95C7F2AD80D507247485CFD4BE0A2EDDB877B3CE385C3ECFE71FF27ECA5D608AED19424037154B56BDB1A36908A09F1A50B1D89A21E6C0FB5C8AD21EC6DD997124DDF07F13BE0058583B070B2DF895223B7FB4A3A00343620436D6DA8114B779BC85CF9DE15C7EB6F26FD49F668FB33073554051B35DD0E5F62A66C47AF7CB3585A56E310FD7FB6336A5923AC5ACD57C72B348A1D8B42F52ABED61BFA58CAEBC9B20531F707C8A07813E66101282C30D86739AAD90790CFE9DE3C5D438318B696BB15BC2160A11FF03211CCEC77939F420BE1B6A8211565332779B86F18DA825F2F1174F4B9DF8C8F6F617648EE78C882688C4CE10C5FDE814B3917FF757AD7FE749129988CC43762002F89B24FADDC2D0926484C0C8B12B9944B177DB4A890E4826F72A4A0E19018781ECE90FB485443C7BE06C20C9DA7055F0AA87706B5A90DDB91834FAF746C2836C7C47496D8A0FD36FDAC574E924F7B514EDD7828215810D7370699C6C6C22D0AF97C289B49B99E4521EE8E8946FFCA48189C6653FA7F81D185E420D39B3BB34EDEC3D672AC0BA3890108400E25ED4CC877729F241E0D5BAED7EFC2BCAFC453BCEF9653C722D62C694420E509968F0BD3AADCCBD4E078B5E5B7E6A7833758167EC693E590982DCD54DCEA98BD3672E486E2A6F64A54366EEE3179636552CB832684B100D2AD75E91D86D7892DB3D7B3565953D35328973DAEF53955D8519B54A812550D8C11DD2A284845394A5395A7BC20F12450DC0C41769A2EDDA0A3256CFCFAF408F2405D31D795A8E1BC8C2A3E324595A96173575EF054F04214B0321A9A607E6DC6FA0EAF5CD0F26A3C1DEB15BDA4DB06E196AA145ED7ACD2E311B5C29AFFB26BC126E37FDBA4ECBE3A171CE7901161D62064B5F6B667D6011CEB90A19B8D05A4D2B1BFDDD8886F8F622F63D7E14D61B87A9177AF6EFCBA41E95BA35B2D0E330F9CAE832EA3CAA46DFBA1CB2D88D96B34F5DE2C12255AF89D0BC7FA9E5AAF1FC0A84CC3B6E9BDF25652A44F0DB30C4CEBE9298373CF54E73DA942D060F112B2F525364A3ACB0D2D3DEE2E7F908202D3E7C8FAEC5CFD7E0E3F506272A405D7486A0A7B2C7D9F3F8FC06222546647AAEB4CCFE00000000000000000000000000000000000000000000000000111E2D37D81C4D8D734FCBFBEADE3D3F8A039FAA2A2C9957E835AD55B22E75BF57BB556AC8
     * @throws Exception
     */
    public void testDilithiumKATSig()
            throws Exception
    {
        byte[] pubK = Hex.decode("dc7bc9a2e0b6dc66823ae4fbde971c0cfc46f9d96bbfbeebb3470ae0a5a0139fdd6a6ce5bc76e94faa9e9250abd4cee02cf1ee46a8e99ce12d7395781fa7519021273da3365519724efbe279add6c35f92c9d42b032832f1bf29ebbecd3ec87a3af3da33c611f7f35fa35acab174024f118979e23bf2fe069269a2ec45fbc1b9c1fb0e1f05486a6a833eb48adc2960641d9af6eb8b7381b1ec55d889f26b084ddfa1c9ed9b962d342694cede83825309d9db6bd6ba7582132534861e44a04388a694242411761d34e7c085d282b723c65948a2ac764d9702bd8ed7fe9931d7d8704a39e6508844f3f84843c305594fe6e5404e08f18ed039ac6563cbaa34b0ca38320299d6256ec0f78d421f088159d49dc439cbc539a55884a3eb4efc9cf190b42f713441cb97004245d41437a39b7b77fc602fbbfd619a42363714b265173cae68fd8a1b3ca2bd30ae60c53e5604577a4a3b1f1506e697c37432dbd883553aac8d382a3d250cf5b29e4d1be2cbcd531ff0e07e89c1f7dbc8d4529aeebe55b5ce4d0214bfdec69e080bd3ef36cca6a54933f1ef2f37867c0d38fd5865b87929115808c7e2595458e993bacc6c5a3b9f5025001e9b41447708bfbaa0462efa63876c42f769908b432f5485508a393224960551d77eadfaf4411cbc49fdff46f2f155ddd6ec30867905b709888ca0f30f935fb8d7f4803cfc7a5f7790ca181d99ca21f2621d69a5c6d49c76b4969da62740a378470332b30947ab31ccdb9ba0c7b625879eec4bd81f0200ba23504a7dc3b118bc2ab1145df13af3c8cc39f577873b84911b3d85fbbf4cb19e4d36b10a938eeb78b599dc86615fd6cec6eb7b8f7afa5f6d6be19ea81630d36ccfb2f487de50d0cf46da8d3fe3512812043c0e3ef2d7231fb0b0a35a0fb283be30a1247780f30ae0294e8b6f5897383edb895595f577524df54593cdf927b4967616ee3913e4d6b29b0dbd7c33a2a45e4ef1b1954ea5d91ce37efc1302e7ce02a97395565da2a5c5d3fdb0d87684e9b1c0ad07ec33df2dfad528e2ea0966d2a47dd5ee88e77d653c0d004fab0165f0757c4da40af327e7192536c79947a80a827aa2107dacfae3debfc8fad3d6e08076d938c510a276bdf6721a1f087cb169515028ad5ce27a1047abd92809934ca63b893f71f9a34a99c0fd30310c47e9aa37394d0ab73b254d3ca69d9c5549c9479aae24264ac5ea64d3fd821c3962ec77e709f9d30bc7b65a52e48c16e80603558caca1811411c3155d1f949fc9cf9aa9385a7199e99be77a66fad7eed91258de55b2c4c83f9a050adebea5f09758f40dac4a1c394ee8d687879150d26426895ab1938e14ae11b376254c91fc6130436996f8ed43bd27be20ec9067111c116ec94cc2b06cc91a13c5d10bbd7eecea4792f17b2b77631ef145e9fb41a83eaa11c2b72a48fb90fdbd88644c4edf8ab20dce3118364b276ac1237b36c8926e346aab5a111aa0bf341c518b7bff9e9dbb8bcb4728601b3760663e67650331e6fb54ac82fc414cb8ddfc160a25311ec5272de46217fef8b992ff89754fbee351f21bb90b6c97078b510c983350681266c8fed1f0583c5151e7b8fe3b7292319699687cc6b641fdbd689428543bc0fa1facc109de65b62784c2d985ab15d77d3af12af6d03e8d1859a553688584d75ef673a1de74093ee108c761fff32c217c231b0e2953daf521429264c0963bc8a5cdeddc617a7285b934ea51ddb5cdab23bcede86be36e001bc65c65e9a1c94baff4fab8eb5f8ed42ec377423633fe00049142467c47c5d58a7202c8e9104841c1f7f380145a6a0a828c570235e507ae5868a6062f722bb98ff6be");
        byte[] privK = Hex.decode("dc7bc9a2e0b6dc66823ae4fbde971c0cfc46f9d96bbfbeebb3470ae0a5a0139ff037b84e75537e0a1cf02a517acfe323ffffe11df72e4f38430e0e66a2654b2f2ef757da47649d9f63fa03f1bf6fe6bc7c62971a98a2bd9d36eb0ec43ad4e9d940df3bb5874f5c92192aa31e0535d3cf70950bba858d11a688eaf854f63ecfc520c50d624891434265d8b0680c03061040299a104082c0910c8508d1100d44a6509408292211125b90508a2688e1302dc4021280028ac302611820851237808a000ae2040421b4910bb80550a08051b2511c28428a3672a494504910201bb45161424424a75001328181942d62a850023449ca94200b296213156408924c48122100b605030208e0060200a311e1802021116483a62898029291480801083041066613200e5b360951400c53000aa08851944842e316704ab2089b92440025121b0309418209c2a0800b290a819851c4340da4424500a0105b048e603400138928a4422648002c90202d194068e2146d19278a083746e4146914006422c660d3a03013242844965014166da0284dcc462e94367100232e1c114909a2040131060a2172c2142ada000c5a260d13228a62c444e3142d013445980224d33841c0308121a621e348720b1984d2c89108b8690887714a2884d496451a9301ca2285da30859ac851dcc00820106060465262302aa224251044640b2842988011540692144251d236719bb4900b082890188e41c469e1a469032160e01409d3020c20c88c1cb23164086218476920228ccb8470089528029550533270013405888424541041d202881aa84ccac88181008d0392899ab809d9900c9a1290614065c9322d89860c123521cc4266c8360010062411028ea3b44d44023043a0285a002ed1980c4882658922441c010212907084226e12134d011902519064113364c91806c2c04589262908b63024308cda022e0c27250b367058162c5116420b4946c1208841246c99466a04434e18a86c821661922028639409c30211029520211782d43868003460c84688e0160000a32dc0a82824b640831464c81022a2086503234ac8122ea098418c2072cc308a62c665093408412682da429089328514967081226001176d5948428ab88d592051d80892e2c0889044700ac0245a020904218a59c45094441094140820460209270c441020dcc8209212015038250c456e4a1666223770dc808ca426412222441ba3618a343099844099c42952046d88146ccb242a7cd129a8d333115c62d033b6a8357cf7cd10268ab12f16fceb7975d0a28a6c4822213c9a772df084ad91a669e2040550fc5e8d0aeb10fab2375fc9625ef9cd48c19631997a1cb6455d2c6286c569c9637add0317ce990996b28e51c3f3f717fb5907bbdd53961ad3497f2c3c473cce170906ac4c624a89aa8fbe624d99385e9c9548bf05e8cafd47d2476e41b73001f813726499e88b2b3b6f596ca311657850346598994c40e34747161e4e76264deef2a3019389d1594c942301af47b7544c23ecda2df2dece81e487d8f3f58ea89cd811d7275807ff1b0369ba86470088c174a3099fdafbe5fbb4d158801053b2b435d54059e26dee76d10a7a372f06b0b88b985b32f52052387438be8dc8bc6ae7369e2da9aa5e2585f8de403d091ccb7f790d54ddb34c608b0876f2825e9113be20a2b85867a01bda53287ac780bcd8b606d2e6d7712c56ce0142d22fe6b786de544963e134fecedfafb83d763061d799096a59e30d4472e440ae1faaabdf42640ce69740ceb9cae1a9612c21931b74af3f780236123321b205b6efd6cbb134f4c73d63c0c13e660b59d5920bc33197c355853d8d1cddc7959f7bc500ac81d985016f5b89a0eec79b0d9364ead8e38577c2a6549f2d067cb09438fdb21220aec80f6e22a476f332a2a4a0b7acbeb9e078d2b5a92ae84c924f7cb19fc7df377beb6546af97aa985c747cd111a127a674b4c26d89c14485b82e3a498a12d05406febd6c4d4b8bc051ab2cb91224b078538374b794b7dd9ddf3ac2b4a671fb7b9cf5acb78622ae2709eb2db16943aa24a9c97a81077bc784d25c0ea5991d2de883798a1f0e78f3361ed6a10dded81b1d683658331534fd7c01bc0eb00dfc4c3c84f0693046ff806bb200dd7bd4c0e6abca3f2934b4814fc0e1f8be615a2dda7c8a8d06cf9ce8566b40f4a6543b25bacddc926863fc0fa2007d6d7bf6d18dc98df696bd0865bf0be4c492b8043a32def8e3595ba7da345252f38f95be10fd7fb899b498fa01b09de5d5608eabc44a721aa04c4ef1dcb86102ac5f5f79c9708dcf5c5e896edd8c2c7bde3fa83e6ffce22d66174e31657a0b6361585e669d3031952f08631ae1f16ff90b90d0aad3c6d7e1dd0a9c41ab00a6e1c4f96af9ac5b79fcf821ffc016cb059245fb78dbe6c633d965aaab5333be07195c4b74b18e4600ce783c0a914ef4281016e80a7c9aa92d0fd789879c5e6751125ecb154432311e41cebd4fab3a31e4d2ce22d0f8c67737bf8a0dd85fe1349d5079a4d5feb3fee9378ca47ae46cc58a3f02038cfd53c4cee9cc4270cebc3d115a39c831e8ed41c4dbe4051b51d7872ba0c2bb163e0085201188eaa624a6bea9400a3a1fcc355a57f15704e61fda55a5dbaea8448fa5cb2d377a07f58305ad107e844ab4806e5bf99c1f513ee1d0a2acc04549f0801742169a77971d0adbfbfe0dd2ee5d16bc461e35748d1f3f6f4598321e8c49e79e740f990359858d2729dde007fcb26fdda9aa6e2ec4bd736f2836e7e4c83440191c849f6a53c72a4f8f830d001ea3b18f3cb4a5bd3cf066032b4932cfd2e62a9b55723fa61c688c935518af6860cd649bfbf1bf5fdc1f36dcaefaa157438d1cc8d56a150161511df82631f5e88e773e4ce263f276b7b3678d4c6fc75311d411c0d01bfdb595bb70552838e1b86517c837d909e772b428599e1fe569f77ce61531fde6fd31cdce1bdee4ba467fcbfbb9feeaad99fef67d4906e036c73662ddce158d4e5d4635e5d366f79f31a19d1b3dc4a591b0df194bb06c18147f41d88d1a409becdfb67eb063d16312266fd51b521ba9115e2e5e2aeae6ec511cede13ed4132ffbe0273f6c7039b3874f058804a54809af60557a21d9b4b831d04156a7c22dcbcdfe14f62437f449cb5ef12bf4251d485496cd835c0c2bc58bd845963dfa76ecd68519c4bdaf110be7ab052876dc3407591568c956ea3bf107c90fd5853a292f59a8d4b58b5d3fddf29bdbeac36852e3c69766fe460176a801831292b8e88a74a01ecbbe09a7b4d74cfd7fd628841944d9d556dbd60c76f96f07dc53443805ee9aa09365de4fb8179252c6b099b5dd351fdefc23dbd8090596c5d208ffd2c5661d8e5612dd574fc69045c769a969e600d77cfe192f1d3ae911289355c585811491b0ccd73692ab158824ab9edf8ac8193f0b33e6138b72c6dcd5d344f807b3da92425037de5ea4eead1c795effaa145e2ecdd327606eb2609929b9474b2bb04653602555c068385e92f06f29ca613ce5b4404f01ab1805db0acaa890330d291f40692df382509302b6dc8668f2c8f2d3a44fd58dca26e9802794f73d25b3149e6d576441");
        byte[] msg = Hex.decode("D81C4D8D734FCBFBEADE3D3F8A039FAA2A2C9957E835AD55B22E75BF57BB556AC8");
        byte[] s = Hex.decode("fcc4f40c043066771043d494eb13181802151a8f82c5c4e29582f6b0fa35023fa7042b68c6630fd99b8152265f4e439ff2430197e57d4195f3bdb6e92e707f964006001f748b94ed0249414226b5f439ab4daa261f9b549f40fd2c690521a5934230c808899473ce5abb67f406a020db59ead7c5eac5c53156a4bb603603b46db9c2fa5f5bf26fbb67c3a98a399ef245d30d761a1adda9d4439d1d1ce86480c2b123e984209fcc830a300b1c8108e320d34a27a752b2d0cec268de0f9f9eee7f4c7cca6f64d8a0288f6c92699cded9cacca31d80e6bb5107af87d1021fc6787d79f001e04a4aabfbaef2b172c5010e6389ab8075496f50558fba91c70e6440640f522b6a38bbe429cfd5352031eb651721823a3705514b6aebb9c3954f79fd01cb228d731d7a41b462cc1a1c855905ff17f14d7f8b71d0f17c03e4239d2881012f94466fcd1e66e62227d6812f8b81157b8954a671391c064838cb215c79fc6fc9d85ef0c891aea9e9ab16500cf06613a02ca82d25decfdbd1a81090b280b4e3213a5db5f7020d30d8169ea176975f72d1910c64684afc2516a35ec35308c4d127fd5c9f54786d2f7ff60c6110514d6bd7720507ec9ede750e4b9929b20ffa65dd714eb11e4e0865c3d2930d8170018e9eb29b72b1e66b7a65afae1617d752ea435f88db7f87dbd29e9859957eb73b766c38675e96d1be9c4404297e6e40b5009fa9adde177980d25bf3b76c130682f8105c1257bd20b9624b09157d2f6ed42dd9b080903603786a0ec3a0d8a847999eb4788f23f1a95db1f5818dadcbad60078a8b1be01d02ac3ee9ba88cf5909a4d4318d9fd2a439aa37e8da68f6208dc5ec3cd659a5aaa3362ad0ff4a3ba6ed5ea75cb710c83bda0afbc14ae4a61e19a0ab4e9597bcfdb9da986308322cd7f534b173f76e0151e693b52bd2029a7ea294bad8ced7ca0485e58c73a71eb5ddc1bfa12f2a0026aec90db969e6cea486e6628903e75275a39a1105aad7abe683660e02b6fc12bd59227358bc20a49eec69b4c03318c90bb3d9725ac1fe6f9609349b14eea21ea996cb118258035213a8fab19339cea94043667cf2ee596c3fb01d136d40450adbf9761d047e6897b975d291a53097b747bc9d6342e91b88bd0a2e7d6444973557ffae72123d84b228131951dda7a10f993f2427a9a9dc822d822363c9517dca0bfffa2f6aa66e3fe5802c05026b72c03813ef26a90855565d419d402ad1b3b1719c2d23637c425eb1cfaa6e5bb82c87735b802ffb1fdd6693385af5f96a73a8e482e9128f428571edd73c1495be9ffb2a6b5a28a1b8a30ec737f82989e328433255e53cb901764f0c0341cb67e5c6275fee34e35c3e6057cc1af790bb111b5a7a2f86de7c680f42d838ac4e8059677c9d382f167af649253f31c00120e797ec93d0a31af80b44ad2fbf0a8a1f67d1a63ee448d85442677f24c60d581555fb6c693bf8829e5062f4b3a66f028c7505600464138d4c026100e55d878434aba2d41d0e90d4dda9e2bd46c337efce479f999cb50adc080575ecebfd1ce6ad6450f9d7ec025c793493e8c11059d3fae194476efd16742fa2d1a399d6cdffc0a6cf1e4e13ec0f515c21846b9da843f2b0af70de17f7bcbc11a2f11e9cb1efa24a28477c0fc5ea4f6a644e608c028e5aab8f82109a07ce8a06e99012593f32051d865f561cfb365312ef49338ceeeb3842ce1ee2381a1641043c32c852a1add433075ddb94863749b3c7dc6ac10e681293deba2a355843a1ead7448f2af81beb5500357a81a5375355941ea2172c96e1cfb84120f93496943d344af409a8573bbf5961d1dd044bc2ce21ad2b7c5c721b324d697e786e711a8c08d358f52b96507b6d380048e4783740ff996610aa6a2b5e6788d68b065717b507bcb2df05e0af6268735bd5e929798ac5e0f12fdab6da267dab9102c6ae20451e644499c2c8408eeeac9abc7130dee6c33144819ef78905b45dbb9fef7ebc92871092a8aebaf9c754544b055fbdc52b760687b15b22d3582e3d881c5afc00b360f504c67fc90ccdb1ee8d8626f7f12596fdf9ba95621bd00a5f6331261da4340d5bc5a4cc222f60d9e220f6e1b56d1492b20d68b75d7cef20df2737821980efca83822f19cb4f5ece26665e6b07c43b65715df26632534e84d7b3d109a5fb026052bc9323a02a41a5d194ef0990713a578219b989b9a5383cb64e4cdd8ab3ca7807895272490b3cf72a01ae21615bf6af12f2283cc1cc400ed660bba87dfe9bc1e26c29c50ff3a01a14f83b52d20116f8b7b3b133810476a38c588d36f85c5c9def402b13e89201aacdacdf2c6ea8cc0e819423e86f080d6690a136ac4879c26e9a45c80a0d5d77d7ec4f0e395ac5bfb0b67d6ba617fff4f3f0bdbf50a383827db69a405590ad8bd752f55ef299800e1a5eeca7dec712b4343cd82ed6cd96c60fa0c65a960105d3717d3391ac116c868202c11b11ef2cdb2e8a3f3df1940c8f98c372c6d9989044b922f48b38e97168ce900a5af99bd9a81cd1e26109bf5de678e5c1d42b8fd29a738ee2125aca3ca9f5dc18a0e36a16bd64c04c498667e95fbc582affcdbc4ef896fcc1971352e2195d235321f750bb5ebb44bc3c411f7129518780dee0fb706ed16cc749753b8ee44ca7008a6922ab90c803002260f6f5c605436306d96c9b7c538a19cef0d35479d1dd5e5874e3b1a2ff4c1b50b942c3f166d7d9e51f870faba93a2ddf2b32b21f7552606af24772b428cf47d473f8a5cd2fab4c1bdbcbcc9abb6d017e2f0f3f18e224c4f3b1f0384021dd8d58e8b62c1f2011cf17343b0cf86774fc8b85882fbfc6e884cfc97bafb90d6381a647aef10dbcfe263863311fb30d91d885b049d41050f461b08de163cbb1b49ae1b4bcd64175bb3b96b154cd2946dd2961b629bd13beda7867c93b31242aaad973db6f92093880461a43071a62b361cff82bae2f32be33f1e36062f8f7ab7fb3c50c8c5ea6d7e0fb023ab994c45e8b43bcc6ace4e7b0529a41842b64aabf0cfa30c5d98f7897ace3074dd75f0f61f228d911def6258b3b3e95487d301ebdd9c80fe323e7929897784c04da3b52c5ff6fee1f28e309bede2ca244af7a30ae146137f472cff9ecfc2d1fb7e20f9108a6c8bcec4cbb877f3fa15820e5e21596949dd4b2d659f3e450d6f5e715cb307da9af905af6f695b519f5af28e2c3bc4c7633f1191486be9969746cc8c0b70405d9c7f77f8cadc2cacd9c492b774902cf9ced338fe612909795ae6c951258faa52b5f5a363ddedf5a10a4d4e8e253242b626f7ec8d5eff9050a393b3e44494b748397afb6cbccd4f8f9fa364955787a878a96a5acc0c6cbd9eaf6123242446e96a8b7c0d7dff1000000000000000000000000000000000000000000000000091c2c38");

        KeyPairGenerator kpg = KeyPairGenerator.getInstance("Dilithium", "BC");
        SecureRandom katRandom = new NISTSecureRandom(Hex.decode("061550234D158C5EC95595FE04EF7A25767F2E24CC2BC479D09D86DC9ABCFDE7056A8C266F9EF97ED08541DBD2E1FFA1"), null);

        kpg.initialize(DilithiumParameterSpec.dilithium2, katRandom);

        KeyPair kp = kpg.generateKeyPair();

        SubjectPublicKeyInfo pubInfo = SubjectPublicKeyInfo.getInstance(kp.getPublic().getEncoded());

        ASN1BitString pubSeq = pubInfo.getPublicKeyData();

        assertTrue(Arrays.areEqual(pubSeq.getOctets(), pubK));

        PrivateKeyInfo privInfo = PrivateKeyInfo.getInstance(kp.getPrivate().getEncoded());
        ASN1OctetString seq = ASN1OctetString.getInstance(privInfo.parsePrivateKey());

        assertTrue(Arrays.areEqual(seq.getOctets(), privK));

        Signature sig = Signature.getInstance("Dilithium", "BC");

        sig.initSign(kp.getPrivate());

        sig.update(msg, 0, msg.length);

        byte[] genS = sig.sign();

        assertTrue(Arrays.areEqual(s, genS));
        
        sig = Signature.getInstance("Dilithium", "BC");

        sig.initVerify(kp.getPublic());

        sig.update(msg, 0, msg.length);

        assertTrue(sig.verify(s));

        // check randomisation

        sig.initSign(kp.getPrivate(), new SecureRandom());

        sig.update(msg, 0, msg.length);

        genS = sig.sign();

        assertFalse(Arrays.areEqual(s, genS));

        sig = Signature.getInstance("Dilithium", "BC");

        sig.initVerify(kp.getPublic());

        sig.update(msg, 0, msg.length);

        assertTrue(sig.verify(s));
    }

    private static class RiggedRandom
            extends SecureRandom
    {
        public void nextBytes(byte[] bytes)
        {
            for (int i = 0; i != bytes.length; i++)
            {
                bytes[i] = (byte)(i & 0xff);
            }
        }
    }
}
